package cn.base.web.auth.uri;

import cn.base.web.auth.token.AuthenTokenManager;
import cn.base.web.authc.AccessControl;
import cn.base.web.authc.DefaultAuthenticator;
import cn.rengy.auth.AuthenToken;
import cn.rengy.auth.Authentication;
import cn.rengy.auth.UserService;
import cn.rengy.auth.entity.principal.Identity;
import cn.rengy.auth.exception.AuthException;
import cn.rengy.auth.pathtree.PathTree;
import cn.rengy.auth.pathtree.UriTree;
import cn.rengy.lang.ResultEntity;
import cn.rengy.util.web.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import java.util.List;

/**
 * uri访问控制
 * 微服务中gateway服务中开启，单体服务中可以选择开启
 */
@ConditionalOnProperty(name = "enable.cn.base.web.auth.uri.UriAccessControl", havingValue = "true",matchIfMissing=true)
@Component
@Slf4j
public class UriAccessControl implements AccessControl {

    @Autowired
    private AuthenTokenManager authenTokenManager;

    @Autowired
    private DefaultAuthenticator defaultAuthenticator;
    @Autowired
    private UserService userService;
    @Override
    public ResultEntity<HttpStatus, Authentication> isAccessAllowed(Object request, Object response) {

        //log.debug("exchange.getRequest().getPath().value()={}",path.value());
        //log.debug("exchange.getRequest().getURI().getPath()={}",uri.getPath());
        //ServerWebExchange exchange=(ServerWebExchange)request;
        String path= RequestUtil.getRequestPath(request);
        String method=RequestUtil.getRequestMethod(request);
        //忽略OPTIONS请求
        if(method.equals(RequestMethod.OPTIONS.name())) {
            return ResultEntity.ok(HttpStatus.OK,null);
        }
        //log.debug("exchange.getRequest().getMethodValue()={}",method);
        //long startTime = System.nanoTime();
        ResultEntity<PathTree.MatchResult, List<String>> match= UriTree.matchUri(path,method);
        PathTree.MatchResult matchResult=  match.getCode();
        //int responseStatus= HttpStatus.UNAUTHORIZED.value();//401
        //String msg="fail";
        if(log.isDebugEnabled()){
            String matchName=matchResult.name();
            if (matchResult == PathTree.MatchResult.author) {
                matchName=matchName.concat(match.getData().toString());
            }
            log.debug("{}==={}==={}",path,method,matchName);
        }
        if(matchResult== PathTree.MatchResult.notFound||matchResult== PathTree.MatchResult.anon){
            return ResultEntity.ok(HttpStatus.OK,null);
        }

        if(matchResult == PathTree.MatchResult.methodNotSupported){
            return ResultEntity.fail(HttpStatus.METHOD_NOT_ALLOWED,"methodNotSupported");
        }
        //需要登录
        AuthenToken authenticationToken=authenTokenManager.getAuthenticationToken(request);
        Authentication authentication=null;
        try {
            authentication=defaultAuthenticator.authenticate(authenticationToken);
        }catch(AuthException e) {
            log.info("[{}]登录失败:{}",authenticationToken.getClass().getName(),e.getMessage());
            return ResultEntity.fail(HttpStatus.UNAUTHORIZED,e.getMessage());
        }
        Identity identity=(Identity)authentication.getPrincipal();
        Long userId=identity.getUserId();
        if (matchResult == PathTree.MatchResult.author) {
            List<String> pathRoles=match.getData();
            if(!userService.hasRoles(userId,pathRoles)){
                return ResultEntity.fail(HttpStatus.FORBIDDEN,"没有权限执行此操作");
            }
        }
        return ResultEntity.ok(HttpStatus.OK,authentication);
    }
}
